<?php

namespace app\common\service;

use app\common\exception\BusinessException;
use app\common\helper\JwtHelper;
use app\common\model\Exam;
use app\common\model\Profession;
use app\common\model\Region;
use app\common\model\User as UserModel;
use app\common\model\UserAuth;
use app\common\model\UserScoreRecord;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;


class UserService
{
    /**
     * isWhiteUser
     * @param int $id
     * @return bool
     * @throws
     */
    public function isWhiteUser(int $id): bool
    {
        // 查询条件
        $where = [
            ['id', '=', $id],
            ['status', '=', 1]
        ];

        // 查询数据
        $whitelist = app(UserModel::class)->where($where)->value('whitelist', 0);
        return $whitelist == 1;
    }

    /**
     * getUserById
     * @param int $id
     * @param string $field
     * @return array
     * @throws
     */
    public function getUserById(int $id, string $field = '*'): array
    {
        //查询条件
        $where = [
            ['id', '=', $id],
            ['status', '=', 1]
        ];

        //查询数据
        $info = app(UserModel::class)->where($where)->find();

        //返回
        return $info ? $info->toArray() : [];
    }

    /**
     * getUserByAllUid
     * @param $allUid
     * @param string $field
     * @return array
     * @throws
     */
    public function getUserByAllUid($allUid, string $field = "*"): array
    {
        // 查询条件
        $where = [
            ['id', 'in', $allUid],
            ['status', '=', 1]
        ];

        // 查询数据
        return app(UserModel::class)->where($where)->field($field)->select()->toArray();
    }

    /**
     * getUserByOpenid
     * @param string $appId
     * @param string $openid
     * @param string $field
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getUserByOpenid(string $appId, string $openid, string $field = '*'): array
    {
        //查询条件
        $where = [
            ['app_id', '=', $appId],
            ['openid', '=', $openid],
        ];

        //查询数据
        $info = app(UserModel::class)->where($where)->field($field)->find();

        //返回
        return $info ? $info->toArray() : [];
    }

    /**
     * getUserByOpenid
     * @param string $appId
     * @param string $unionid
     * @param string $field
     * @return array
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getUserByUnionid(string $appId, string $unionid, string $field = '*'): array
    {
        //查询条件
        $where = [
            ['app_id', '=', $appId],
            ['unionid', '=', $unionid],
            ['status', '=', 1]
        ];

        //查询数据
        $info = app(UserModel::class)->where($where)->find();

        //返回
        return $info ? $info->toArray() : [];
    }

    /**
     * getUserByMobile
     * @param string $appId
     * @param string $mobile
     * @return array
     * @throws
     */
    public function getUserByMobile(string $appId, string $mobile): array
    {
        // 查询条件
        $where = [
            ['app_id', '=', $appId],
            ['mobile', '=', $mobile],
            ['status', '=', 1]
        ];

        // 查询数据
        $info = app(UserModel::class)->where($where)->find();

        // 返回
        return $info ? $info->toArray() : [];
    }

    /**
     * getUserByAuth
     * @param $identity
     * @param $password
     * @return array
     */
    public function getUserByAuth($appId, $identity, $password): array
    {
        // 查询条件
        $where = [
            'app_id' => $appId
        ];
        $where1 = [
            'password' => $password
        ];
        $where2 = [
            'email' => $identity,
            'mobile' => $identity,
            'username' => $identity
        ];

        // 查询数据
        $info = app(UserModel::class)->where($where)->where($where1)->where(
            function ($query) use ($where2) {
                $query->whereOr($where2);
            }
        )->find();

        //返回
        return $info ? $info->toArray() : [];
    }

    /**
     * getUserByName
     * @param string $username
     * @return array
     */
    public function getUserByName(string $username): array
    {
        $info = app(UserModel::class)->where('username', '=', $username)->find();
        return $info ? $info->toArray() : [];
    }

    /**
     * setUserToWhitelist
     * @throws BusinessException
     */
    public function setUserToWhitelist($uid)
    {
        $where = [
            'id' => $uid
        ];
        $time = time();
        $isUpdate = app(UserModel::class)->where($where)->update([
            'whitelist' => 1,
            'update_time' => $time,
        ]);
        if (!$isUpdate) {
            throw new BusinessException('更新白名单失败');
        }
    }

    /**
     * setUserToAgent
     * @throws BusinessException
     */
    public function setUserToAgent($uid)
    {
        $where = [
            'id' => $uid
        ];
        $time = time();
        $isUpdate = app(UserModel::class)->where($where)->update([
            'is_agent' => 1,
            'update_time' => $time,
        ]);
        if ($isUpdate === false) {
            throw new BusinessException('更新代理失败');
        }
    }

    /**
     * setUserInfoById
     * @throws BusinessException
     */
    public function setUserInfoById($id, $data)
    {
        $where = ['id' => $id];
        $isUpdate = app(UserModel::class)->where($where)->update($data);
        if ($isUpdate === false) {
            throw new BusinessException('更新用户信息失败');
        }
    }

    /**
     * checkMobileExist
     * @param string $appId
     * @param string $mobile
     * @return bool
     * @throws
     */
    public function checkMobileExist(string $appId, string $mobile): bool
    {
        $where = ['app_id' => $appId, 'mobile' => $mobile];
        return (bool)app(UserModel::class)->where($where)->count();
    }

    /**
     * checkUsernameExist
     * @param string $username
     * @return bool
     * @throws
     */
    public function checkUsernameExist(string $username): bool
    {
        $where = ['username' => $username];
        return (bool)app(UserModel::class)->where($where)->count();
    }

    /**
     * checkUsernameExistByOpenid
     * @param string $openid
     * @return bool
     * @throws
     */
    public function checkExistByOpenid(string $openid): bool
    {
        $where = ['openid' => $openid];
        return (bool)app(UserModel::class)->where($where)->count();
    }

    /**
     * 会员增加积分
     * @param int $uid
     * @param int $score
     * @param int $source
     * @throws BusinessException
     */
    public function sendScoreToUid(int $uid, int $score, int $source)
    {
        //启动事务
        $userModel = new UserModel();
        $userModel->startTrans();


        //类型增加来源:1.注册账号  2.登录账号   3.绑定微信   4.绑定邮箱  5.分享好友

        //1.增加积分
        $where = [['id', '=', $uid]];
        if (!$userModel->where($where)->inc('score', $score)->update()) {
            //回滚事务
            $userModel->rollback();
            throw new BusinessException('充值积分失败');
        }

        //2.记录日志
        if (!app(UserScoreRecord::class)->add($uid, 1, $score, $source)) {
            //回滚事务
            $userModel->rollback();
            throw new BusinessException('充值积分时保存日志失败');
        }

        //提交事务
        $userModel->commit();
    }

    /**
     * 会员扣除积分
     * @param int $uid
     * @param int $score
     * @param $remark
     * @param int $source
     * @throws BusinessException
     */
    public function deductScoreToUid(int $uid, int $score, $remark = '', $source = 0)
    {
        // 启动事务
        $userModel = new UserModel();
        $userModel->startTrans();

        //1.减少积分
        if (!$userModel->where([['id', '=', $uid], ['score', '>=', $score]])->dec('score', $score)->update()) {
            //回滚事务
            $userModel->rollback();
            throw new BusinessException('积分不足');
        }

        //2.记录流水
        if (!app(UserScoreRecord::class)->add($uid, 2, $score, $source, $remark)) {
            //回滚事务
            $userModel->rollback();
            throw new BusinessException('扣除失败');
        }

        // 提交事务
        $userModel->commit();
    }

    /**
     * buildAuthKey
     * @param  $userId
     * @return string
     * @throws
     */
    public function buildAuthKey($userId, $redirectUrl = ''): string
    {
        // 生成Token
        $token = JwtHelper::create($userId, config('mcp.tokenExpire'));

        // 查询学生信息
        $info = $this->getUserById($userId);
        if ($info['exam_id']) {
            $examInfo = app(Exam::class)->where(['id' => $info['exam_id']])->find();
            $examInfo = $examInfo ? $examInfo->toArray() : [];
        }
        if ($info['region_id']) {
            $regionInfo = app(Region::class)->where(['id' => $info['region_id']])->find();
            $regionInfo = $regionInfo ? $regionInfo->toArray() : [];
        }
        if ($info['profession_id']) {
            $professionInfo = app(Profession::class)->where(['id' => $info['profession_id']])->find();
            $professionInfo = $professionInfo ? $professionInfo->toArray() : [];
        }

        // 生成登录tokenKey+保存用户信息+保存缓存
        $authKey = md5($token);
        $authVal = [
            'info' => $info,
            'tokenInfo' => $token,
            'examInfo' => $examInfo ?? [],
            'regionInfo' => $regionInfo ?? [],
            'professionInfo' => $professionInfo ?? [],
            'redirectUrl' => $redirectUrl,
        ];

        // 查询数据
        $where = [
            'auth_key' => $authKey
        ];
        $count = app(UserAuth::class)->where($where)->count();

        // 保存数据
        $time = time();
        $saveData = [
            'auth_key' => $authKey,
            'auth_val' => json_encode($authVal),
            'create_time' => $time,
            'update_time' => $time,
        ];
        if (!$count) {
            $isInsert = app(UserAuth::class)->insert($saveData);
            if (!$isInsert) {
                throw new BusinessException('保存用户安全信息失败');
            }
        } else {
            unset($saveData['create_time']);
            $isUpdate = app(UserAuth::class)->where($where)->update($saveData);
            if (!$isUpdate) {
                throw new BusinessException('更新用户安全信息失败');
            }
        }

        // 返回
        return $authKey;
    }

    /**
     * getAuthVal
     * @throws
     */
    public function getAuthVal($authVal)
    {
        // 查询条件
        $where = [
            'auth_key' => $authVal
        ];

        // 查询数据
        $info = app(UserAuth::class)->where($where)->find();
        if (!$info) {
            return [];
        }

        // 转换数据
        $authVal = json_decode($info['auth_val'], true);
        if (!$authVal) {
            throw new BusinessException('解密安全信息失败');
        }

        // 返回
        return $authVal;
    }

    /**
     * getUserByAllUid
     * @param $allUid
     * @param string $field
     * @return array
     * @throws
     */
    public function getAgentByAllUid($allUid, string $field = "*"): array
    {
        // 查询条件
        $where = [
            ['id', 'in', $allUid],
            ['status', '=', 1],
            ['is_agent', '=', 1]
        ];

        // 查询数据
        return app(UserModel::class)->where($where)->field($field)->select()->toArray();
    }

    /**
     * getActiveUsers
     * @param int $days
     * @param string $field
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function getActiveUsers(int $days = 1, string $field = '*', int $limit = 1000)
    {
        // 查询条件
        $time = time() - 86400 * $days;
        $where = [
            ['update_time', '>=', $time],
        ];

        // 查询数据
        return app(UserModel::class)->where($where)->field($field)->limit($limit)->select()->toArray();
    }

    /**
     * 检查手机号码是否可绑定
     * @param $appId
     * @param $mobile
     * @param $uid
     * @return bool
     * @throws DbException
     */
    public function checkMobileCanBind($appId, $mobile, $uid): bool
    {
        // 查询条件
        $where = [
            ['app_id', '=', $appId],
            ['mobile', '=', $mobile],
        ];
        if (!$uid) {
            $count = app(UserModel::class)->where($where)->count();
        } else {
            // 查询小于
            $where1 = $where;
            $where1[] = ['id', '<', $uid];
            $count = app(UserModel::class)->where($where1)->count();

            // 查询大于
            $where2 = $where;
            $where2[] = ['id', '>', $uid];
            $count += app(UserModel::class)->where($where2)->count();
        }
        return $count == 0;
    }
}